// SelectionSet.h
//
#ifndef SELECTIONSET_H
#define SELECTIONSET_H

#include <list>
#include <map>

////---------------------------------------------------------------------------------------------
///**
//  * Selection Policy.
//  * Enumerator containing selection policies
//  *
//  * @author D. Vacca
//  * @updated 14-sep-2009
//  */
//
//// --------------------------------------------------------------------------------------------
//// Simple structure to handle multiple requests
//template <typename T>
//class SelectionRequest
//{
//public:
//	// --------------------------------------------------------------------------------------------
//	std::vector<T> types;
//	std::vector<int> reqQty;
//	std::vector<int> currQty;
//	int totObjectRequested;
//	// --------------------------------------------------------------------------------------------
//	
//public:
//	// --------------------------------------------------------------------------------------------
//	SelectionRequest(T t, int qty)
//	{
//		// ignore quantities on negative values of qty
//
//		types.clear();
//		reqQty.clear();
//		currQty.clear();
//
//		types.push_back(t);
//		reqQty.push_back(qty);
//		currQty.push_back(qty);
//		totObjectRequested = qty;
//	}
//
//	// --------------------------------------------------------------------------------------------
//	SelectionRequest(std::vector<T> t, std::vector<int> qty)
//	{
//		types.clear();
//		reqQty.clear();
//		currQty.clear();
//		totObjectRequested = 0;
//
//		for(size_t i=0; i<t.size(); ++i)
//		{
//			types.push_back(t[i]);
//			reqQty.push_back(qty[i]);
//			currQty.push_back(qty[i]);
//			totObjectRequested += qty[i];
//		}
//	}
//};

class SelectionSet
{
public:
	enum SelectionPolicy
	{
		PolicyExclusive,
		PolicyAdd
	};

	typedef std::list<unsigned int>							 SelectionList;		// list of object identifiers
	typedef std::map<unsigned int, SelectionList::iterator>  SelectionIndex;	// auxiliary indexing map for faster searches <Key=objID,value=>


private:
	SelectionList   _selectionList;
	SelectionIndex  _selectionIndex;
	SelectionPolicy _selectionPolicy;

	//std::vector<SelectionRequest<GeometricType> >		requests;
	//int									totReqCount;	// how many objects are currently requested

public:
	SelectionSet();
	~SelectionSet();

	bool addObject( unsigned int objID );
	bool removeObject( unsigned int objID );

	// --------------------------------------------------------------------------------------------
	//void addRequest(SelectionRequest<GeometricType> req)
	//{
	//	if (totReqCount < 0)
	//		totReqCount = 0;

	//	for(size_t i=0; i<req.types.size(); ++i)
	//		if(req.reqQty[i] > 0)
	//			totReqCount += req.reqQty[i];
	//		else
	//			totReqCount = -1; //

	//	requests.push_back(req);
	//}

	//// --------------------------------------------------------------------------------------------
	//void setDefaultRequest()
	//{
	//	totReqCount = -1;
	//	requests.clear();
	//}
	//
	//// --------------------------------------------------------------------------------------------
	//// useful to re-apply requests without changing the selectionset
	//void refresh()
	//{
	//	SelectionList tmp;	
	//	selectionList.swap(tmp);
	//	for(SelectionList::iterator it = tmp.begin(); it != tmp.end(); ++it)
	//		addObject(it->first, it->second, it->second->getGeometricType());
	//}


	// --------------------------------------------------------------------------------------------
	//void setRequest(std::vector<GeometricObjectType> types, std::vector<int> num)
	//{
	//	assert( types.size() == num.size() ); // invalid Selection request?

	//	// reset request
	//	reqObj.clear();
	//	reqNum.clear();
	//	currReqObj.clear();
	//	totalRequests = 0;
	//	
	//	// set the requested types
	//	for(size_t i=0; i<types.size(); ++i)
	//	{
	//		reqObj.push_back(types[i]);
	//		reqNum.push_back(num[i]);
	//		currReqObj.push_back(num[i]);
	//		totalRequests += num[i];
	//	}

	//	// something went wrong...reset the selection request
	//	if(totalRequests == 0)
	//	{
	//		reqObj.clear();
	//		reqNum.clear();
	//		currReqObj.clear();
	//		totalRequests = -1;
	//	}
	//}

	// --------------------------------------------------------------------------------------------
	//bool isRequestFulfilled(SelectionFulFillMode mode, bool selectOnlyRequestedObjects = true)
	//{
	//	bool fulfill = false;
	//	int objCount = 0;
	//	
	//	if(mode == FulFillModeAtLeastOne)
	//	{
	//		for(size_t i=0; i<requests.size(); ++i)
	//		{
	//			int k = 0;
	//			for(size_t j=0; j<requests[i].types.size(); ++j)
	//			{
	//				if(requests[i].currQty[j] == 0)
	//					k += requests[i].reqQty[j];
	//			}

	//			if( k == requests[i].totObjectRequested || requests[i].totObjectRequested < 0 )
	//			{
	//				fulfill = true;
	//				objCount = k;
	//				break;
	//			}
	//		}
	//	}
	//	else if(mode == FulFillModeAll)
	//	{
	//		// @TODO:
	//		//fulfill = true;
	//		//for(size_t i=0; i<requests.size(); ++i)
	//		//{
	//		//	for(size_t j=0; j<requests[i].types.size(); ++j)
	//		//	{
	//		//		if(requests[i].currQty[j] != 0)
	//		//		{
	//		//			fulfill = false;
	//		//			break;
	//		//		}
	//		//		else
	//		//			objCount += requests[i].reqQty[j];
	//		//	}
	//		//}
	//	}

	//	if (selectOnlyRequestedObjects)
	//	{
	//		if( selectionList.size() == 0		|| 
	//			selectionList.size() != objCount)
	//			fulfill = false;
	//	}
	//	else
	//	{
	//		if( selectionList.size() == 0 )
	//			fulfill = false;
	//	}

	//	return fulfill;
	//}

	// --------------------------------------------------------------------------------------------
	void clear();


	// --------------------------------------------------------------------------------------------
	//void restoreRequest()
	//{
	//	//requests.clear();
	//	totReqCount = 0;
	//	
	//	for(size_t i=0; i<requests.size(); ++i)
	//	{
	//		for(size_t j=0; j<requests[i].types.size(); ++j)
	//		{
	//			requests[i].currQty[j] = requests[i].reqQty[j];
	//			totReqCount += requests[i].reqQty[j];
	//		}
	//	}

	//	if(totReqCount == 0) 
	//		totReqCount = -1;
	//}

	// --------------------------------------------------------------------------------------------
	//bool hasRequests()						{return requests.size() >0;}
	
	// --------------------------------------------------------------------------------------------
	// --------------------------------------------------------------------------------------------
	SelectionList &get()					      { return _selectionList; }
	void setPolicy(SelectionPolicy policy)	      { _selectionPolicy = policy; }
	SelectionPolicy getPolicy()				const { return _selectionPolicy; }
	bool isEmpty()							const { return _selectionList.empty(); }
};

#endif